
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"

#include "App_Lora.h"
#include "crc.h"

QueueHandle_t Queue_LoraRec;   //Lora接收消息队列


#define TXD_PIN (GPIO_NUM_17)
#define RXD_PIN (GPIO_NUM_16)


//LoRa M0
#define LORA_M0_PIN     GPIO_NUM_25
//LoRa M1
#define LORA_M1_PIN     GPIO_NUM_26
//选择初始化Lora引脚宏
#define LORA_GPIO_OUTPUT_PIN_SEL    (1ULL<<GPIO_NUM_25)|(1ULL<<GPIO_NUM_26) //配置GPIO_OUT寄存器
//1ULL = unsigned long long 也就是uin64_t  这里是需要和pin_bit_mask的类型一样~


#define LORA_M0(x)      gpio_set_level(LORA_M0_PIN, x)
#define LORA_M1(x)      gpio_set_level(LORA_M1_PIN, x)
//枚举定义：Lora模式
enum lora_mode
{
    lora_mode_transfer,
    lora_mode_wor,
    lora_mode_conf,
    lora_mode_sleep
};
 


void UART2_Init(void)
{
    const uart_config_t uart_config = {
        .baud_rate = 9600,                      //波特率
        .data_bits = UART_DATA_8_BITS,          //数据位
        .parity = UART_PARITY_DISABLE,          //奇偶校验
        .stop_bits = UART_STOP_BITS_1,          //停止位
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,  //流控制
        .source_clk = UART_SCLK_DEFAULT,        //时钟源
    };
    // We won't use a buffer for sending data.
    uart_driver_install(UART_NUM_2, 2048, 0, 0, NULL, 0);       //安装串口驱动程序：串口2，接收Buff，发送Buff
    uart_param_config(UART_NUM_2, &uart_config);                //配置串口2
    uart_set_pin(UART_NUM_2, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); //将UART的信号分配给GPIO引脚

}


void LoRa_GPIO_Init(void)
{
    gpio_config_t io_conf;                  //定义GPIO配置结构体
    io_conf.intr_type = GPIO_INTR_DISABLE;  //禁止中断  
    io_conf.mode = GPIO_MODE_OUTPUT;        //选择输出模式
    io_conf.pin_bit_mask = LORA_GPIO_OUTPUT_PIN_SEL;               //设置GPIO_OUT寄存器
    io_conf.pull_down_en = 0;               //禁止上拉
    io_conf.pull_up_en = 0;                 //禁止下拉
    gpio_config(&io_conf);                  //初始化
}

void LoRa_Rx_Task(void *arg)
{
    uint8_t i = 0;
    uint8_t data;
	uint8_t last_data = 0;
	
	uint8_t isRecv = false;	//接收状态
	uint8_t *recv = NULL;	//用于指向开辟接收的数组的指针

    while (1)
    {
        uart_read_bytes(UART_NUM_2, &data, 1, portMAX_DELAY);   //接收一个数据
        // printf("LoRa_Rx:%x\r\n", data);
        //处理接收到的数据
        if(last_data == LR_FRAME_HEAD_H && data == LR_FRAME_HEAD_L && !isRecv)
			{
				//判断为帧头
				isRecv = true;	//标记接收
				i = 0;
				recv = pvPortMalloc(MAX_FRAME_LEN); //开辟内存，单位为字节，大小32byte
				memset(recv, 0, MAX_FRAME_LEN);
			}else if(last_data == LR_FRAME_END_H && data == LR_FRAME_END_L && isRecv)
			{
				//判断为帧尾
				recv[i-1] = '\0';	//将帧尾替换为\0
                xQueueSend(Queue_LoraRec, recv,portMAX_DELAY);  //将接收到的数据放入队列中
				vPortFree(recv);		//释放内存
				isRecv = false;	//标记接收完毕
				recv = NULL;	//指针置空
				i = 0;
			}else if(isRecv && i < MAX_FRAME_LEN){
				recv[i++] = data;
			}else{
				//其他情况直接释放内存，重头开始
				if(isRecv)
                    vPortFree(recv);
				recv = NULL;
				i = 0;
			}
			//记录上一个消息
			last_data = data;
    }
}


void Lora_RX_data_parse(uint8_t* recv_buf)
{
    //提取此次接收的数据长度
	uint8_t recv_length = recv_buf[0];
 
    #if DEBUG
        // 输出接收到的 除去帧头帧尾的值
        printf("Received data: ");
        for (int i = 0; i <= recv_length; i++) {
            printf("%02X ", recv_buf[i]);
        }
        printf("\n");
    #endif
        
        // 接收到的数据至少大于2
        if (recv_length < 2) {
            //错误处理
            return;
        }
        // 提取接收数据中的 CRC
        uint16_t recv_crc = (recv_buf[recv_length - 1] << 8) | recv_buf[recv_length];
        // 计算 CRC16
        uint16_t calculated_crc = CRC16(recv_buf, recv_length - 2 + 1);	//包含数据长度位
        // 校验 CRC16
        if (calculated_crc == recv_crc) {
            // CRC16 校验通过，处理有效数据
            switch (recv_buf[1]) { 			// 定位从机地址
                case 0x02:              //从机1
                    
                    break; // 查询命令
               
                default:
                    printf("Unknown slave: %02X\n", recv_buf[1]);
                    break;
            }
        } else {
            // CRC16 校验失败
            printf("CRC16 check failed! Received CRC: %04X, Calculated CRC: %04X\n", recv_crc, calculated_crc);
            return;
        }
}

//Lora接收的有效信息的处理  线程
void Lora_RX_data_parse_Task(void* arg)
{
	uint8_t* recv_buf = NULL;   //接收数据缓存区
	while(1)
	{
		// 为 recv_buf 分配内存
        recv_buf = pvPortMalloc(MAX_FRAME_LEN);
        if (recv_buf == NULL) {
			//报错处理
            continue;
        }
		// 等待 接收消息队列的 数据
		BaseType_t result = xQueueReceive(Queue_LoraRec, recv_buf, portMAX_DELAY); //接收消息队列中的数据
		
		if(result == pdPASS)    //从接收消息队列中 接收数据成功
		{
			Lora_RX_data_parse(recv_buf);	//判断命令
			
			vPortFree(recv_buf);	//释放空间
		}
		
	}
}


//Lora模块 模式配置函数
void lora_mode_config(enum lora_mode mode)
{
    //vTaskDelay等待滴答，而不是ms，需要正确地转换它。解决方案: vTaskDelay(1000/portTICK_PERIOD_MS)；
    vTaskDelay(100/portTICK_PERIOD_MS);
    switch(mode)
    {
        case lora_mode_transfer : LORA_M0(0); LORA_M1(0); break;
        case lora_mode_wor      : LORA_M0(1); LORA_M1(0); break;
        case lora_mode_conf     : LORA_M0(0); LORA_M1(1); break;
        case lora_mode_sleep    : LORA_M0(1); LORA_M1(1); break;
        default                 : break;
    }
    vTaskDelay(100/portTICK_PERIOD_MS);
}

void Lora_Init(void)
{
    //配置Lora模块的地址和信道
    lora_mode_config(lora_mode_conf);   //配置模式
    lora_Master_t lora_master = {
        .addr_h = 0x00,         //地址高位
        .addr_l = 0x01,         //地址低位
        .channel = 0x17,        //信道
    }; 
    uint8_t con[10] = {0xC0, 0x00, 0x07, 
                        lora_master.addr_h, 
                        lora_master.addr_l, 
                        0x04, 0x62, 0x00, 
                        lora_master.channel, 0x40}; 
    uart_write_bytes(UART_NUM_2,con, 10);

    // 开启发送模式
    lora_mode_config(lora_mode_transfer);
}

//Lora模块查询函数
uint8_t lora_query(uint8_t* buf, lora_Slave_t slave, lora_frame_query_t frame)
{
    uint8_t sendbuf[32] = {0}; //数据缓存区
    uint16_t crc = 0; //CRC校验值

    sendbuf[0] = slave.addr_h;         //地址高位
    sendbuf[1] = slave.addr_l;         //地址低位
    sendbuf[2] = slave.channel;        //信道

    sendbuf[3] = LR_FRAME_HEAD_H;   //帧头高位
    sendbuf[4] = LR_FRAME_HEAD_L;   //帧头低位

    sendbuf[5] = 0x00;     //数据长度
    sendbuf[6] = 0xaa;              //查询命令
    sendbuf[7] = frame.module;     //模块码
    sendbuf[8] = frame.register_addr; //寄存器地址

    sendbuf[9] = 0x00;         //crc高位
    sendbuf[10] = 0x00;        //crc低位

    sendbuf[11] = LR_FRAME_END_H; //帧尾高位
    sendbuf[12] = LR_FRAME_END_L; //帧尾低位

    sendbuf[5] = 5;  //帧长度 = 命令码 + 模块码 + 寄存器地址 + CRC高位 + CRC低位
    crc = CRC16(&sendbuf[5], 4);    //校验 帧长度 + 命令码 + 模块码 + 寄存器地址 的CRC16值
    sendbuf[9] = (crc >> 8) & 0xFF; //CRC高位
    sendbuf[10] = crc & 0xFF;       //CRC低位

    memcpy(buf, sendbuf, sizeof(sendbuf)); //将数据缓存区的内容复制到buf中

    return 13; //返回数据长度
}

//Lora模块设置函数
uint8_t lora_set(uint8_t *buf, lora_Slave_t slave, lora_frame_set_t frame)
{
    uint8_t sendbuf[32] = {0}; //数据缓存区
    uint16_t crc = 0; //CRC校验值

    sendbuf[0] = slave.addr_h;         //地址高位
    sendbuf[1] = slave.addr_l;         //地址低位
    sendbuf[2] = slave.channel;        //信道

    sendbuf[3] = LR_FRAME_HEAD_H;   //帧头高位
    sendbuf[4] = LR_FRAME_HEAD_L;   //帧头低位

    sendbuf[5] = 0x00;              //数据长度
    sendbuf[6] = 0x55;              //设置命令
    sendbuf[7] = frame.module;     //模块码
    sendbuf[8] = frame.register_addr; //寄存器地址
    sendbuf[9] = frame.data[0]; //数据高位
    sendbuf[10] = frame.data[1]; //数据低位

    sendbuf[11] = 0x00;         //crc高位
    sendbuf[12] = 0x00;        //crc低位
   
    sendbuf[13] = LR_FRAME_END_H; //帧尾高位
    sendbuf[14] = LR_FRAME_END_L; //帧尾低位

    sendbuf[5] = 7;  //帧长度 = 命令码 + 模块码 + 寄存器地址 + 数据高位 + 数据地位 + CRC高位 + CRC低位
    crc = CRC16(&sendbuf[5], 6);    //校验 帧长度 + 命令码 + 模块码 + 寄存器地址 + 数据高位 + 数据低位 的CRC16值
    sendbuf[11] = (crc >> 8) & 0xFF; //CRC高位
    sendbuf[12] = crc & 0xFF;       //CRC低位

    memcpy(buf, sendbuf, sizeof(sendbuf)); //将数据缓存区的内容复制到buf中

    return 15; //返回数据长度
}
void App_Lora_Init(void)
{
    UART2_Init();       //初始化串口2
    LoRa_GPIO_Init();   //初始化Lora引脚
    Lora_Init();        //初始化Lora模块

    //创建接收Lora任务
    xTaskCreate(LoRa_Rx_Task, "LoRa_Rx_Task", 1024 * 2, NULL, configMAX_PRIORITIES - 1, NULL);
    //创建lora接收消息队列
    Queue_LoraRec = xQueueCreate(32, MAX_FRAME_LEN); //创建消息队列，队列长度为32，单个消息长度为MAX_FRAME_LEN
    //创建Lora接收数据处理任务
    xTaskCreate(Lora_RX_data_parse_Task, "Lora_RX_data_parse_Task", 1024 * 2, NULL, configMAX_PRIORITIES - 1, NULL);
    //从机的地址和信道配置
    lora_Slave_t lora_slave = {
        .addr_h = 0x00,         //地址高位
        .addr_l = 0x02,         //地址低位
        .channel = 0x17,        //信道
    };

    //查询数据
    lora_frame_query_t lora_frame_query = {
        .module = LR_MODULE_TEST_LED,         //模块码
        .register_addr = LR_REG_TEST_LED_STATE,  //寄存器地址
    };

    //设置数据
    lora_frame_set_t lora_frame_set = {
        .module = LR_MODULE_TEST_LED,         //模块码
        .register_addr = LR_REG_TEST_LED_STATE,  //寄存器地址
        .data[0] = 0x02,                     //数据高位 反转
        .data[1] = 0x00,                     //数据低位
    };

    uint8_t msgs[32] = {0}; //数据缓存区
    //uint8_t len lora_query(msgs, lora_slave, lora_frame_query); //查询数据
    uint8_t len = lora_set(msgs, lora_slave, lora_frame_set); //设置数据

    uart_write_bytes(UART_NUM_2, msgs, len);  //发送数据


    //调试--打印输出数据
    for (uint8_t j = 0; j < len; j++)
    {
        printf("out: %x\r\n", msgs[j]);
    }
}
